/**
 * Created by oneminute on 14-6-7.
 */
var arango = require("arango");
var async = require("async");
var moment = require("moment");
var fs = require("fs");
var program = require('commander');
var lz = require("../utils/modules")();

program
    .version('0.0.1')
    .option('-i, --init', 'Init test datas in cache.')
    .option('-d, --database [dbname]', 'The arango dababase name.')
    .option('-g, --gendatas', 'Generate datas.')
    .option('-r, --removedb', 'Remove database.')
    .option('-b, --baseid [baseid]', 'Base Id')
    .parse(process.argv);

var database = program.database || lz.Config.db.arango.database;
lz.Config.db.arango.database = database;
lz.Logger.debug("initDatas: database: ", database);

function linear(_hotPosition, _callback) {
    var layerTimes = 3;
    var layers = [];
    var total = 1;
    var lastCount = 1;
    while (lastCount < _hotPosition.count) {
        layers.push(lastCount);
        lastCount = lastCount * layerTimes;
        if ((total + lastCount) > _hotPosition.count) {
            layers.push(_hotPosition.count - total);
            break;
        }
        total += lastCount;
    }
    var layerCount = layers.length;
    lz.Logger.info("", _hotPosition, layerCount);
    layers.forEach(function (_count, _index) {
        var radianTile = Math.PI * 2 / _count;
        var radius = _hotPosition.radius * _index / layerCount;
        for (var i = 0; i < _count; i++) {
            var loc = lz.Utils.calculateLocationApproximate(_hotPosition.location, radius, radianTile * i);
            lz.Logger.info("layer %d, radius %d, radianTile %d, lon %d, lat %d", _index, radius, radianTile, loc.lon, loc.lat);
            _callback(_hotPosition, loc);
        }
    });
}

function rand(_hotPosition, _callback) {
    for (var i = 0; i < _hotPosition.count; i++) {
        var radius = Math.random() * _hotPosition.radius;
        var radian = Math.random() * Math.PI * 2;
        var loc = lz.Utils.calculateLocationApproximate(_hotPosition.location, radius, radian);
        _callback(_hotPosition, loc);
    }
}

function HotPosition(_options) {
    this.location = _options.location || {
        lon: 0,
        lat: 0
    };
    this.radius = _options.radius || 3000;
    this.minCount = _options.minCount || 100;
    this.maxCount = _options.maxCount || 10000;
    this.fixCount = _options.fixCount || false;
    this.count = _options.count || this.maxCount;
    this.fn = _options.fn || linear;
}

HotPosition.prototype.generateSamples = function (_callback) {
    if (!this.fixCount)
        this.count = Math.floor(Math.random() * (this.maxCount - this.minCount) + this.minCount);

    this.fn(this, _callback);
};

exports.linear = linear;
exports.rand = rand;
exports.HotPosition = HotPosition;

exports.initArangoDB = function (_cb) {
    lz.Logger.info("initArangoDB: 开始初始化Arango数据库。");
    var db = arango.Connection(lz.Config.db.arango.url);

    db.database.delete(database, function (_err, _ret, _message) {
        if (_err)
            lz.Logger.error("delete db: error", _err, _ret);
        lz.Logger.info("删除数据库%s成功。", database);
        db.database.create(database, function (_err, _ret, _message) {
            if (_err)
                lz.Logger.error("create db: ", _err, _ret);
            lz.Logger.info("创建数据库%s成功。", database);
            _cb(null);
        });
    });
};

exports.initCollection = function (_coll, _cb) {
    lz.Logger.info("iinitCollection: 开始创建%s集合。", _coll);
    var newdb = arango.Connection({
        _name: database,
        _server: {
            hostname: "localhost"
        }
    });
    var options = {
        waitForSync: false,
        keyOptions: {
            allowUserKeys: true
        }
    };

    newdb.collection.delete(_coll, function (_err, _ret, _message) {
        newdb.collection.create(_coll, options, function (_err, _ret) {
            if (_err)
                lz.Logger.error("初始化%s错误: ", _coll, _err, _ret);
            lz.Logger.info("初始化%s完毕。", _coll);
            _cb(null);
        });
    });
};

exports.initUsersCollection = function (_cb) {
    lz.Logger.info("initUsersCollection: 开始创建User集合。");
    exports.initCollection(lz.Config.db.arango.users, _cb);
};

exports.initCommoditiesCollection = function (_cb) {
    lz.Logger.info("initCommoditiesCollection: 开始创建Commodity集合。");
    exports.initCollection(lz.Config.db.arango.commodities, _cb);
};

exports.initGiftsCollection = function (_cb) {
    lz.Logger.info("initUsersCollection: 开始创建User集合。");
    exports.initCollection(lz.Config.db.arango.gifts, _cb);
};

exports.initDemandsCollection = function (_cb) {
    lz.Logger.info("initDemandsCollection: 开始创建Demands集合。");
    exports.initCollection(lz.Config.db.arango.demands, _cb);
};

exports.initEmailsCollection = function (_cb) {
    lz.Logger.info("initEmailsCollection: 开始创建Email集合。");
    exports.initCollection(lz.Config.db.arango.emails, _cb);
};

exports.initAccountsCollection = function (_cb) {
    lz.Logger.info("initAccountsCollection: 开始创建Account集合。");
    exports.initCollection(lz.Config.db.arango.accounts, _cb);
};

exports.initIssuesCollection = function (_cb) {
    lz.Logger.info("initIssuesCollection: 开始创建Issue集合。");
    exports.initCollection(lz.Config.db.arango.issues, _cb);
};

exports.initMessagesCollection = function (_cb) {
    lz.Logger.info("initMessagesCollection: 开始创建Message集合。");
    exports.initCollection(lz.Config.db.arango.messages, _cb);
};

exports.initMessageCodesCollection = function (_cb) {
    lz.Logger.info("initMessageCodesCollection: 开始创建MessageCode集合。");
    exports.initCollection(lz.Config.db.arango.codes, _cb);
};

exports.initRecordsCollection = function (_cb) {
    lz.Logger.info("initRecordsCollection: 开始创建Records集合。");
    exports.initCollection(lz.Config.db.arango.records, _cb);
};

exports.createGeoIndex = function (_cb) {
    lz.Logger.info("createGeoIndex: 开始创建Geo索引。");
    var db = arango.Connection({
        _name: database,
        _server: {
            hostname: "localhost"
        }
    });
    lz.Logger.info("开始创建Geo索引。");
    db.index.createGeoSpatialIndex(lz.Config.db.arango.users, ['lat', 'lon'], function (_err, _ret, _message) {
        if (_err) {
            lz.Logger.error("创建Geo索引失败。", _ret);
            _cb(true);
        }
        lz.Logger.info("message.status=", _message.status);
        lz.Logger.info("成功创建Geo索引。");
        _cb(null);
    });
};

exports.initTestingDatas = function (_callback) {
    lz.Logger.debug("开始初始化测试数据到缓存。");
    var poses = [
        new HotPosition({
            fixCount: true,
            count: 1000,
            radius: 20000,
            fn: linear,
            location: {
                lon: 115.985504,
                lat: 36.465117
            }
        }),
        new HotPosition({
            fixCount: true,
            count: 1000,
            radius: 30000,
            fn: linear,
            location: {
                lon: 117.118489,
                lat: 36.694713
            }
        }),
        new HotPosition({
            fixCount: true,
            count: 1000,
            radius: 8000,
            fn: linear,
            location: {
                lon: 117.061326,
                lat: 36.693829
            }
        })
    ];
    var users = [];
    var i = 0;
    var tasks = [];
    var baseId = parseInt(program.baseid || 1000000);
    poses.forEach(function (_pos) {
        _pos.generateSamples(function (_hotPos, _loc) {
            var uid = lz.Utils.getUUID("u_");
            var name = ("" + (baseId + i++)).substring(1);
            var password = name;
            var commodities = [];
            var demands = [];
            for (var j = 0; j < 5; j++) {
                var commodity = {
                    id: lz.Utils.getUUID("c_"),
                    uid: uid,
                    description: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
                    price: Math.random() * 500,
                    photos: ["7a66aec0f2e111e38d4239a1595329eb.png", "7a66aec0f2e111e38d4239a1595329eb.png", "7a66aec0f2e111e38d4239a1595329eb.png", "7a66aec0f2e111e38d4239a1595329eb.png"],
                    publishDate: moment().format(lz.Config.datetimeFormatLong)
                };

                var demand = {
                    id: lz.Utils.getUUID("d_"),
                    uid: uid,
                    description: "debug_demand_desc" + j,
                    publishDate: moment().format(lz.Config.datetimeFormat),
                    expireDate: moment().format(lz.Config.datetimeFormat),
                    publishDate: moment().format(lz.Config.datetimeFormat)
                };
                commodities.push(commodity);
                demands.push(demand);
            }
            var user = new lz.User({
                id: uid,
                name: name,
                password: password,
                lon: _loc.lon,
                lat: _loc.lat,
                phone: "18652163487",
                loginPhone: "18600" + name,
                photo: "4f93be80f4fe11e38d4239a1595329eb.png",
                address: "testing address",
                description: "an testing description",
                inbusiness: true,
                email: {
                    email: name + "@lz.com",
                    uid: uid,
                    authenticated: false,
                    authtime: moment().format(lz.Config.datetimeFormatLong),
                    authcode: ""
                },
                accounts: [
                    {
                        id: lz.Utils.getUUID("b_"),
                        uid: uid,
                        account: "q_" + name,
                        publisher: "qq"
                    },
                    {
                        id: lz.Utils.getUUID("b_"),
                        uid: uid,
                        account: "w_" + name,
                        publisher: "weixi"
                    }
                ],
                commodities: commodities,
                demands: demands
            });

            tasks.push(function (_cb) {
                user.save(function (_err, _user) {
                    if (_err) {
                        lz.Logger.error(_err);
                    }
                    lz.Logger.info("%d完成。", _user.name);
                    _cb(_err);
                });
            });
            lz.Logger.info("initTestingDatas: 第%d个", i);
        });
    });

    async.series(tasks, function () {
        lz.Logger.info("generate testing datas completed.");
        _callback(null);
    });
};

exports.init = function () {
    var self = this;
    // 检查数据库是否存在，不存在则运行初始化程序。
    var actions = [];
    if (program.removedb) {
        actions.push(this.initArangoDB);
        actions.push(this.initUsersCollection);
        actions.push(this.initCommoditiesCollection);
        actions.push(this.initGiftsCollection);
        actions.push(this.initDemandsCollection);
        actions.push(this.initEmailsCollection);
        actions.push(this.initAccountsCollection);
        actions.push(this.initIssuesCollection);
        actions.push(this.initMessagesCollection);
        actions.push(this.initMessageCodesCollection);
        actions.push(this.initRecordsCollection);
        actions.push(this.createGeoIndex);
    }

    if (program.gendatas) {
        actions.push(this.initTestingDatas);
    }
    async.series(actions, function () {
        lz.Logger.info("初始化完毕。");
    });
};

if (program.init) {
    this.init();
}
